﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using TV_Organizer.Properties;
using System.ComponentModel;
using System.Windows.Data;
using System.Threading.Tasks;

namespace TV_Organizer.Subtitles
{
    /// <summary>
    /// Logique d'interaction pour SubtitlesControl.xaml
    /// </summary>
    public partial class SubtitlesControl : UserControl
    {
        public SubtitlesControl()
        {
            InitializeComponent();

            this.Files = new CollectionViewSource()
            {
                Source = FileScanner.FileScanner.Instance.Files,
            };
            this.Files.Filter += FilesFilter;

            BindingOperations.SetBinding(this.FilesListView, ListView.ItemsSourceProperty, new Binding()
            {
                Source = this.Files,
            });

            this.SubtitlesListView.Items.SortDescriptions.Add(new SortDescription(File.SubtitleContainer.SimilarityPercentagePropertyName, ListSortDirection.Descending));
            this.SubtitlesListView.Items.SortDescriptions.Add(new SortDescription("Subtitle." + Subtitle.LanguageProperty.Name, ListSortDirection.Ascending));
            this.SubtitlesListView.Items.SortDescriptions.Add(new SortDescription("Subtitle." + Subtitle.FilenameProperty.Name, ListSortDirection.Ascending));

            var languages = TV_Organizer.Language.ValidLanguages.ToList();
            languages.Insert(0, TV_Organizer.Language.All);
            this.LanguageComboBox.ItemsSource = languages;
            BindingOperations.SetBinding(this.LanguageComboBox, ComboBox.SelectedIndexProperty, new Binding()
            {
                Path = new PropertyPath("SubtitlesLanguage"),
                Source = Settings.Default,
            });
            this.LanguageComboBox.SelectionChanged += (o, e) => Settings.Default.Save();
        }

        public CollectionViewSource Files { get; private set; }

        private async void DownloadSelectedSubtitlesButton_Click(object sender, RoutedEventArgs e)
        {
            // Force running outside of main thread
            if (Application.Current.Dispatcher.CheckAccess())
            {
                TaskEx.Run(() => this.DownloadSelectedSubtitlesButton_Click(sender, e));
                return;
            }
            
            var tasks = new List<Task<bool>>();

            var connector = ConnectorsManager.Instance.GetTVSubtitlesConnector(Settings.Default.SelectedSubtitlesConnector);
            if (connector == null)
            {
                App.Instance.Window.Notify("No subtitle connector found. Subtitles will not be downloaded.");
                return;
            }

            var files = FileScanner.FileScanner.Instance.Files;

            App.Instance.Window.ProgressBarMinimum = 0;
            App.Instance.Window.ProgressBarValue = 0;
            App.Instance.Window.ProgressBarMaximum = files.Select(f => f.Subtitles.Where(s => s.Subtitle.IsSelected).Count()).Sum();
            App.Instance.Window.DisplayBusyIndicator("Downloading subtitles...", "Episode");

            foreach (var file in files)
            {
                var usedFilenames = new List<string>();
                foreach (var subContainer in file.Subtitles.Where(s => s.Subtitle.IsSelected))
                {
                    var path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(file.Path),
                        string.Format("{0}.srt", this.GetUniqueNameWhithoutExtension(usedFilenames, System.IO.Path.GetFileNameWithoutExtension(file.Path), subContainer.Subtitle.Language)));
                        
                    var task = connector.DownloadSubtitleAsync(subContainer.Subtitle, path);
                    task.ContinueWith((result) => App.Instance.Window.ProgressBarValue++);
                    tasks.Add(task);
                }
            }

            // After all the tasks are over, update the progress bar and text
            await TaskEx.Run(() => Task.WaitAll(tasks.ToArray()));

            App.Instance.Window.HideBusyIndicator();
        }

        private string GetUniqueNameWhithoutExtension(ICollection<string> alreadyUsedNames, string name, Language language)
        {
            var languageSuffix = Settings.Default.IncludeLanguageInSubtitlesFileNames ? "-" + language.ShortName : "";

            int i = 1;
            var l_result = name + languageSuffix;
            
            while (alreadyUsedNames.Contains(l_result))
            {
                l_result = string.Format("{0}{1}.{2}", name, languageSuffix, i);
                i++;
            }
            alreadyUsedNames.Add(l_result);
            return l_result;
        }

        private async void SearchSubtitlesButton_Click(object sender, RoutedEventArgs e)
        {
            // Force running outside of main thread
            if(Application.Current.Dispatcher.CheckAccess())
            {
                TaskEx.Run(() => this.SearchSubtitlesButton_Click(sender, e));
                return;
            }

            var tasks = new List<Task>();
            var connector = ConnectorsManager.Instance.GetTVSubtitlesConnector(Settings.Default.SelectedSubtitlesConnector);
            if (connector == null)
            {
                App.Instance.Window.Notify("No subtitle connector found. Subtitles will not be downloaded.");
                return;
            }

            var files = this.FilesListView.Items.OfType<File>().ToList();

            App.Instance.Window.ProgressBarMinimum = 0;
            App.Instance.Window.ProgressBarValue = 0;
            App.Instance.Window.ProgressBarMaximum = files.Count;
            App.Instance.Window.DisplayBusyIndicator("Searching subtitles...", "Episode");

            foreach (var file in files)
            {
                if (file.SelectedShow == null || file.Season < 0 || file.Episode < 0) continue;

                var task = this.SearchSubtitlesForAsync(connector, file);
                task.ContinueWith((t) => App.Instance.Window.ProgressBarValue++);
                tasks.Add(task);
            }
            await TaskEx.Run(() => Task.WaitAll(tasks.ToArray()));

            App.Instance.Window.HideBusyIndicator();
            //App.Instance.Window.Notify("{0} subtitles found for {1} files.", tasks.Select(t => t.Result).Sum(), files.Count);
        }

        private async Task SearchSubtitlesForAsync(ITVSubtitlesConnector connector, File file)
        {
            var task = connector.SearchSubtitlesForAsync(file.SelectedShow, new Episode(file.Season, file.Episode, file.EpisodeTitle));
            await task;

            if (task.Result.Count() > 0)
            {
                Application.Current.Dispatcher.BeginInvoke(new System.Action<File, IEnumerable<Subtitle>>(async (file2, subs) =>
                {
                    file2.Subtitles.Clear();
                    await file2.AddSubtitlesAsync(subs);

                    var sortedSubs = file2.Subtitles.OrderByDescending(s => s.SimilarityPercentage).Select(s => s.Subtitle).ToList();
                    if (this.LanguageComboBox.SelectedValue.ToString() == TV_Organizer.Language.All.LongName)
                    {
                        foreach (var language in TV_Organizer.Language.ValidLanguages)
                            this.SelectSubtitle(sortedSubs, language);
                    }
                    else
                    {
                        var language = this.LanguageComboBox.SelectedItem as Language;
                        if (language != null)
                            this.SelectSubtitle(sortedSubs, language);
                    }
                }), new object[] { file, task.Result });
            }
        }

        private void SelectSubtitle(IEnumerable<Subtitle> sortedSubtitles, Language language)
        {
            var sub = sortedSubtitles.FirstOrDefault(s => s.Language == language);
            if (sub != null)
                sub.IsSelected = true;
        }

        private void FilesFilter(object sender, FilterEventArgs e)
        {
            e.Accepted = e.Item is File && ((File)e.Item).IsMediaFile;
        }

        private void SubtitlesListView_PreviewMouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var subContainer = e.OriginalSource.GetDataContext<File.SubtitleContainer>();
            if (subContainer == null) return;

            subContainer.Subtitle.IsSelected = !subContainer.Subtitle.IsSelected;
        }
    }
}
